package com.zhou.cloud.aop.aspect;

import com.zhou.cloud.annotation.ZookeeperLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @descrition: zookeeper lock aop加锁
 * @author: zhouyongjun
 * @date: 2022/11/1
 **/
@EnableAspectJAutoProxy
@Slf4j
@Aspect
@Component
public class ZookeeperLockAspect {
    @Autowired
    @Lazy
    CuratorFramework client;
    @Pointcut("@annotation(com.zhou.cloud.annotation.ZookeeperLock)")
    public void pointCut(){}

    @Around("pointCut()")
    public Object executeLock(ProceedingJoinPoint pjp) throws Throwable  {
        Method method = ((MethodSignature)pjp.getSignature()).getMethod();
        ZookeeperLock annotation = method.getAnnotation(ZookeeperLock.class);
        InterProcessLock lock = null;
        try {
            if (annotation.reentrant()){
                lock = new InterProcessMutex(client,annotation.key());
            }else {
                lock = new InterProcessSemaphoreMutex(client,annotation.key());
            }
            boolean isLock = lock.acquire(annotation.waitTime(),annotation.timeUnit());
            if (!isLock) {
                throw new Exception();
            }
            log.info("lock mutex={}",lock);
            return pjp.proceed();
        }catch (Exception e){
            throw e;
        }
        finally {
            if (lock != null && lock.isAcquiredInThisProcess()) {
                try {
                    lock.release();
                    log.info("release mutex={}",lock);
                } catch (Exception e) {
                    log.error("release error",e);
                }
            }
        }
    }

}
